package MonteCarloMonoThread;

import java.util.Random;
import java.util.concurrent.ConcurrentHashMap;

import javax.swing.JLabel;

import View.MonteCarloGUI;
import View.Updatable;

/**
 * Mono thread calculation for the MonteCarlo Simulation
 * @author adrien
 *
 */


public class MonteCarloMonoThreadSimulation implements Runnable {

	private String CallPutFlag; //"c" for call and "p" for put
	private double S,X,T,r,b,v;
	private int nSteps,nSimulations;
	private Updatable viewToUpdate;
	private double result;
	private JLabel labelResult, labelTime, labelThread;
	private double timeStart;
	ConcurrentHashMap<Integer, Integer> threadIDMap = new ConcurrentHashMap<Integer, Integer>();
	
	
	public MonteCarloMonoThreadSimulation(Updatable viewToUpdate, JLabel labelResult,JLabel labelTime,JLabel labelThread,String callPutFlag, double s, double x,double t, double r, double b, double v, int nSteps, int nSimulations) {
		super();
		CallPutFlag = callPutFlag;
		S = s;
		X = x;
		T = t;
		this.r = r;
		this.b = b;
		this.v = v;
		this.nSteps = nSteps;
		this.nSimulations = nSimulations;
		this.viewToUpdate=viewToUpdate;
		this.labelResult = labelResult;
		this.labelTime = labelTime;
		this.labelThread = labelThread;
	}
	
	public void run(){
		double dt, St, Sum =0, Drift, vSqrdt;
		int i,j,z=0;
		Random random;
		result = 0;
		timeStart = System.currentTimeMillis(); //initialize time
		double nbSimu = nSimulations;
		double nbSimuDone = 0;
		int progress =0;
		
		viewToUpdate.addLabelWest(labelResult);
		viewToUpdate.addLabelEast(labelTime);
		viewToUpdate.addLabelCenter(labelThread);
		
		
		
		dt = T / nSteps ;
		Drift = (b-v*v /2) * dt ;
		vSqrdt = v * java.lang.Math.sqrt(dt);
		
		if (CallPutFlag.equals("c"))z = 1;
		if (CallPutFlag.equals("p"))z = -1;
		
		for (i=0;i<nSimulations;i++) {
			St = S;
			random= new Random(5);
			for (j=0;j<nSteps;j++){
				St = St * java.lang.Math.exp(Drift + vSqrdt * random.nextGaussian());
			}
			Sum = Sum + Math.max(z * (St-X), 0);
			nbSimuDone++;
			progress = (int) (nbSimuDone/nSimulations*100);
			viewToUpdate.setProgressBar(progress);
			
		}
		result =  java.lang.Math.exp(-r * T) * (Sum / nSimulations);
		
		this.addThreadID((int) Thread.currentThread().getId());
		
		
		viewToUpdate.displayIntermediateValue((System.currentTimeMillis()-timeStart)/1000,labelTime);
		viewToUpdate.displayIntermediateValue(result,labelResult);
		viewToUpdate.displayIntermediateValue(this.countThread(),labelThread);
		viewToUpdate.setProgressBar(0);
		System.gc();
		
  	}
	
	public int countThread(){
		return threadIDMap.size();
	}
	
	public void addThreadID(int threadID){
		threadIDMap.putIfAbsent(threadID,0);
	}
		
	
	public static void main (String [] args){
		MonteCarloGUI view = new MonteCarloGUI();
		JLabel labelResult = new JLabel();
		JLabel labelTime = new JLabel();
		JLabel labelThread = new JLabel();
		MonteCarloMonoThreadSimulation mcs= new MonteCarloMonoThreadSimulation((Updatable)view,labelResult,labelTime,labelThread,"c",40,50,0.5,0.06,0.10,0.45,168,100000);
		
		double timeStart = System.currentTimeMillis();
		
		mcs.run();
		
		double timeEnd = System.currentTimeMillis();
		
		System.out.println("Time needed : " + (timeEnd-timeStart)/1000 + " s");
		
	}
	
	
}
